<template>
  <div class="component-cropper">
    <div class="cropper dialog">
      <transition name="fade">
        <div class="dialog-mask" v-show="visible"></div>
      </transition>
      <div class="dialog-wrap" :class="{'wrap--hide': !isWrapShow}">
        <div class="dialog-center-fixed">
          <transition name="ease">
            <div class="dialog-main" v-show="visible">
              <div class="dialog-content">
                <div class="body">
                  <div class="loading-wrapper" v-if="loading">
                    <div class="loading">
                      <svg class="circular" viewBox="25 25 50 50">
                        <circle class="path" cx="50" cy="50" r="20" fill="none"></circle>
                      </svg>
                    </div>
                  </div>
                  <div class="error-wrapper" v-if="error">
                    <div class="error">
                      <img src="./assets/img_error.svg" alt="">
                      <p>上传失败，点击<span class="re-upload" @click="reUpload">重新上传</span></p>
                    </div>
                  </div>
                  <div class="img-container">
                    <img ref="image" src="./assets/picture.jpg" alt="" />
                  </div>
                </div>
                <div class="footer">
                  <div class="btns">
                    <span class="btn cancel" @click="cancel">取消</span>
                    <span class="btn ok" :class="{'disabled': disabled}" @click="ok">确定</span>
                  </div>
                </div>
              </div>
            </div>
          </transition>
        </div>
      </div>
    </div>

    <div class="upload">
      <div class="upload-wraper">
            <input
                ref="fileInput"
                type="file"
                accept="image/*"
                @change="onChangeFileHandler"
            />
            <div class="upload-img" v-if="headImg" @click="handleUpload">
                <img :src="headImg"/>
                <div class="upload-img-mask"><span>重新上传</span></div>
            </div>
            <div class="upload-btn-wrap" @click="handleUpload" v-else>
                <i class="iconfont icon-shangchuan"></i><span>点击上传</span>
            </div>
            <div class="upload-tips">文件不能超过{{size}}</div>
      </div>
    </div>
  </div>
</template>

<script>
import { genUUID } from '@/lib/uuid';
import { getFileExtension, formatFileSize } from './core/helper.js';
import QiniuKodo from './core/uploader.js';
import Cropper from './core/cropper.min.js'
import './core/cropper.min.css';

const defaultOptions = {
  viewMode: 1,
  dragMode: 'move',
  rotatable: false,
  scalable: false,
  toggleDragModeOnDblclick: false,
  wheelZoomRatio: 0.5,
  zoomOnTouch: false
}

export default {
  mounted() {
    this.uploadClient = new QiniuKodo();
    this.headImg = this.modelValue && this.modelValue.attachmentUrl || '';
  },

  props: {
    options: {
      type: Object,
      default: () => {}
    },
    height: {
      type: Number,
      default: 360
    },
    width: {
      type: Number,
      default: 360
    },
    limitSize: { // 单位Kb
      type: Number,
      default: 1024
    },
    modelValue: {
        type: Object,
        default: () => {}
    }
  },
  data() {
    return {
      visible: false,
      isWrapShow: false,

      loading: false,
      error: false,
      cropper: null,

      uploadClient: null,
      authority: null,
      headImg: null
    }
  },
  computed: {
    aspectRatio() {
      if (this.width || this.height) {
        return this.width / this.height;
      }
      return NaN;
    },
    disabled() {
      return this.loading;
    },
    size(){ // 格式化为带单位的数据
        return formatFileSize(this.limitSize * 1024);
    },
    randomColor() {
        let index = Math.floor(Math.random() * 4) + 1;
        return `color-${index}`;
    }
  },
  watch: {
    visible(visible) {
      if (visible) {
        if (this.timer) clearTimeout(this.timer);

        this.isWrapShow = true;
      } else {
        this.timer = setTimeout(() => {
          this.isWrapShow = false
        }, 300);
      }
    },
    isWrapShow(flag) {
      if (!flag) {
        if (this.cropper) {
          this.cropper.destroy();
          this.cropper = null;
        }
      }
    },
    modelValue(val){
        if(val){
            this.headImg = val.attachmentUrl
        }
    }
  },

  methods: {
    cancel() {
      this.visible = false;
    },
    ok() {
      if (this.disabled) return false;

      if (this.cropper) {
        const cropData = this.cropper.getData();
        const uri = this.processUriByCropData(cropData);

        this.$emit('on-ok', uri);
        this.visible = false;
        this.headImg = uri;
        this.$emit('update:modelValue', uri);
      }
    },

    onChangeFileHandler(ev) {
      if (ev.currentTarget.files && ev.currentTarget.files.length) {
        const file = ev.currentTarget.files[0];

        if(file.size > this.limitSize * 1024){
          this.$emit('on-error', {
            code: 10001,
            message: `文件不能超过${this.size}`
          })
          return;
        }
        
        if (/^image\/\w+/.test(file.type)) {
          this.loading = true;
          this.visible = true;

          // 先上传，再裁剪
          this.upload(file);
          this.file = file;
        } else {
          this.$emit('on-error', {
            code: 10001,
            message: '文件类型错误，请选择图片类型的文件'
          })
        }

        ev.target.value = null;
      }
    },
    handleUpload() {
      this.$refs.fileInput.click();
    },

    reUpload() {
      this.error = false;
      this.loading = true;

      this.upload(this.file);
    },

    getUploadToken() {
      return this.$store
        .dispatch('proxyAction', {
          name: 'getMaterialUploadToken',
          message: false
        })
        .then(({ code, data }) => {
          if (code === 200) {
            return data;
          }
        })
        .catch(() => {
          this.authority = null;
          this.$emit('on-error', {
            code: 20001,
            message: '获取权限失败，请尝试重新上传'
          });
        });
    },
    async upload(file) {
      if (this.authority === null) {
        this.authority = await this.getUploadToken();
      }

      if (this.authority) {
        const uuidKey = genUUID();
        const extension = getFileExtension(file.name);
        const callback = {
          onSuccess: this.onSuccess,
          onError: this.onError
        };
        const saveKey = `${this.authority.uploadDate}${uuidKey}.${extension}`;
        const token = this.authority.token;

        this.uploadClient.run(file, saveKey, token, callback);
      }
    },
    onSuccess(response) {
      const uri = this.authority.host + response.key;
      const img = this.$refs.image;

      // 初始化裁剪器
      this.initCropper(uri, img);
      this.file = null;
    },
    onError(info) {
      if (info.code === 401) { // 401. token invalid
        this.authority = null;
      }
      this.loading = false;
      this.error = true;
    },

    /**
     * qiniu:
     *  - imageMogr2/crop/!{cropsize}a<dx>a<dy>   eg. ?imageMogr2/crop/!250x250a10a20
     *  - roundPic/radius/<radius>    eg. ?roundPic/radius/!50p
     */
    processUriByCropData(cropData) {
      const { x, y, width, height } = cropData;
      const imageUrl = this.$refs.image.src;

      return `${imageUrl}?imageMogr2/crop/!${Math.round(width)}x${Math.round(height)}a${Math.round(x)}a${Math.round(y)}`;
    },

    initCropper(uri, img) {
      let options = Object.assign({}, defaultOptions, this.options, {
        aspectRatio: this.aspectRatio,
        ready: () => {
          this.loading = false;
        }
      });

      img.src = uri;
      img.onload = () => {
        if (this.cropper) {
          this.cropper.destroy();
        }
        this.cropper = new Cropper(img, options);
      }
    }
  },

  unmounted() {
    if (this.cropper) {
      this.cropper.destroy();
    }
  }
}
</script>

<style lang="scss" scoped>
@import "./index.scss";

.component-cropper {
  .cropper {
    .body {
      position: relative;
      padding: 10px 16px;
      height: 360px;
      background-color: #FFFFFF;

      .loading-wrapper {
        position: absolute;
        bottom: 0;
        right: 0;
        left: 0;
        top: 0;
        z-index: 2;
        background-color: hsla(0, 0%, 100%, .95)
      }
      .loading {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);

        .circular {
          display: inline;
          height: 40px;
          width: 40px;
          animation: loading-rotate 2s linear infinite;

          .path {
            stroke: #409EFF;
            stroke-dashoffset: 0;
            stroke-dasharray: 90,150;
            stroke-linecap: round;
            stroke-width: 3;
            animation: loading-dash 1.5s ease-in-out infinite;
          }
        }
      }

      .error-wrapper {
        position: absolute;
        bottom: 0;
        right: 0;
        left: 0;
        top: 0;
        z-index: 1;
        background-color: hsla(0, 0%, 100%, .95)
      }
      .error {
        text-align: center;
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        font-size: 12px;
        img {
          width: 80px;
        }
        .re-upload {
          cursor: pointer;
          color: #5293F5;
        }
      }

      .img-container {
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100%;

        img {
          max-height: 100%;
          max-width: 100%;
        }
      }
    }
    .footer {
      border-top: 1px solid #DCDFE6;
      display: flex;
      justify-content: flex-end;
      padding: 10px 16px;

      .btns {
        .btn {
          display: inline-block;
          padding: 10px 20px;
          margin: 0 0 0 10px;
          border: 1px solid #DCDFE6;
          border-radius: 4px;
          line-height: 1;
          font-size: 14px;
          color: #606266;
          cursor: pointer;
          user-select: none;
          &:hover {
            background-color: #ECF5FF;
            border-color: #C6E2FF;
            color: #409EFF;
          }
        }
        .ok {
          background-color: #409EFF;
          border-color: #409EFF;
          color: #FFF;

          &:hover {
            background-color: #66B1FF;
            border-color: #66B1FF;
            color: #FFF;
          }
          &.disabled {
            background-color: #A0CFFF;
            border-color: #A0CFFF;
            color: #FFF;
            cursor: not-allowed;
          }
        }
      }
    }
  }

 
  .upload {
    .upload-wraper{
      display: flex;
      align-items: center;
    }
    .upload-img{
        width: 70px;
        height: 70px;
        display: inline-block;
        overflow: hidden;
        border: 1px solid #E4E7ED;
        border-radius: 4px;
        position: relative;
        user-select: none;

        img{
            width: 100%;
            height: auto;
            object-fit: contain;
            object-position: center;
        }

        &:hover{
          .upload-img-mask{
              display: block;
          }
        }
    }
    .upload-img-mask{
        text-align: center;
        position: absolute;
        top: 0px;
        left: 0px;
        bottom: 0px;
        right: 0px;
        line-height: 70px;
        background: #00000065;
        transition: all 0.2s;
        display: none;
        cursor: pointer;
        span{
          font-size:12px;
          color:#ffffff;
        }
        &.upload-img-btn{
            flex-direction: column;
            align-items: center;
            justify-content: center;
            line-height: auto !important;
        }
        .span-upload{
            line-height: 14px;
            margin-top: 4px;
        }
        i{
            color:#ffffff;
            line-height: 1;
        }
    }
    .upload-btn-wrap {
        display: flex;
        flex-direction: column;
        align-items: center;
        width: 70px;
        height: 70px;
        background: #F5F6F9;
        border-radius: 4px;
        cursor: pointer;
        user-select: none;
        border: 1px dashed #E2E6ED;
        justify-content: center;
        span{
            height: 14px;
            font-size: 12px;
            transform: scale(0.83);
            display: inline-block;
            font-family: PingFangSC-Regular, PingFang SC;
            font-weight: 400;
            color: var(--color-primary);
            line-height: 14px;
            margin-top:4px;
        }
        i{
            color:#949BAF;
            line-height: 1;
        }
    }
    .upload-tips {
        height: 17px;
        font-size: 12px;
        font-family: PingFangSC-Regular, PingFang SC;
        font-weight: 400;
        color: var( --main-text-tip);
        line-height: 17px;
        display: inline-block;
        margin-left: 8px;
    }

    input[type="file"] {
      display: none;
    }
    .upload-img-default{
        width: 70px;
        height: 70px;
        background: #E8EAFD;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        overflow: hidden;
        position: relative;
        .span-name{
            font-size: 20px;
            font-family: PingFangSC-Medium, PingFang SC;
            font-weight: bold;
            color: #5254A9;
            line-height: 28px; 
        }

        &.color-1{
            background: #E8EAFD;
            .span-name{
                color: #5254A9;;
            }
        }
        &.color-2{
            background: #FCF0DD;
            .span-name{
                color: #8D5C2C;
            }
        }
        &.color-3{
            background: #DFF0F8;
            .span-name{
                color: #597DA4;;
            }
        }
        &.color-4{
            background: #E7F6D9;
            .span-name{
                color: #6A9F57;;
            }
        }

        &:hover{
          .upload-img-mask{
             display: flex;
          }
        }
    }
  }
}
</style>